#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "smset.h"
#include "gprs.h"
#include "pdu.h"
#include "object.h"


#define    DIM(x)  (sizeof(x)/sizeof(x[0])) 

//错误信息对应处理句柄
typedef struct sm_error_handle
{
    char type;
    char *info;
}sm_error_handle_t;

static int __view_dp_info(char value, option_t *option); //显示大棚温湿度数据，通过短信发送
static int __view_tel_num(void); //显示报警手机号，通过短信发送

static int _sm_inner_cmd_handle_view_dp(char cmd, char dp_num); //显示大棚数据
static int _sm_inner_cmd_handle_view_tel(char cmd, char value);//查询手机号
static int _sm_inner_cmd_handle_balance(char cmd, char param);//处理余额信息
static int _sm_inner_cmd_handle_query(char cmd, char param);//发送短信查询余额
static int _sm_inner_cmd_handle_set_time(char cmd, char param); //执行设置时间
static int _sm_inner_cmd_handle_ring_ATH(char cmd, char param);//解析挂断来电
static int _sm_inner_cmd_handle_check_sim(char cmd, char param);
static int _sm_inner_cmd_handle_call_phone(char cmd, char param); //拨打报警手机
static int _sm_inner_cmd_handle_hard_reboot(char cmd, char param); //模块硬件重启
static int _sm_cmd_handle_SMS_flush(char cmd, char param); //flush短信缓冲区

/*内部指令*/
// +------+---------+--------------------------------------------------------+
// | CMD  | PARAM   |                    DESCRIPTION                         |
// +------+---------+--------------------------------------------------------+
// |  1   | 大棚号  | 查询对应大棚温湿度，包括当前值、上下限                 |
// +------+---------+--------------------------------------------------------+
// |      |   0     | 查询所有大棚的当前温湿度                               |
// +------+---------+--------------------------------------------------------+
// |  2   |   N     | 查询手机号                                             |
// +------+---------+--------------------------------------------------------+
// |  3   |         | 检查sim卡注册状态                                      |
// +------+---------+--------------------------------------------------------+
// |  4   | 报警值  | 手机余额的最小值，低于最小值报警                       |
// +------+---------+--------------------------------------------------------+
// |  5   | 余额值  | 查询余额，发送查询短信                                 |
// +------+---------+--------------------------------------------------------+
// |  6   |   N     | 拨打报警手机号                                         |
// +------+---------+--------------------------------------------------------+
// |  7   |   N     | 设置系统时间，使用l_time_cclk_string                   |
// +------+---------+--------------------------------------------------------+
// |  8   |   N     | 解析PDU短信                                            |
// +------+---------+--------------------------------------------------------+
// |  9   |   N     | 设置系统时间，使用l_time_cclk_string                   |
// +------+---------+--------------------------------------------------------+
// |  10  |   N     |                                                        |
// +------+---------+--------------------------------------------------------+
//
#define     CCLK_TIME_STRING_BUFFER_LEN 35
static char l_time_cclk_string[CCLK_TIME_STRING_BUFFER_LEN];


const cmd_fifo_cmd_handle_t l_inner_cmd_handle[]=
{           
    /*[CMD_QUERY_DP         ]*/ {_sm_inner_cmd_handle_view_dp}, //查询大棚温湿度
    /*[CMD_QUERY_TEL        ]*/ {_sm_inner_cmd_handle_view_tel},//查询手机号
    /*[CMD_QUERY_SIM_REGSTAT]*/ {_sm_inner_cmd_handle_check_sim},   //检查sim卡注册状态
    /*[CMD_PROC_BALANCE     ]*/ {_sm_inner_cmd_handle_balance},     //处理余额
    /*[CMD_QUERY_BALANCE    ]*/ {_sm_inner_cmd_handle_query},   //发送短信查询余额
    /*[CMD_CALL_PHONE       ]*/ {_sm_inner_cmd_handle_call_phone},  //拨打报警手机号
    /*[CMD_SET_SYS_TIME     ]*/ {_sm_inner_cmd_handle_set_time},//设置系统时间
    /*[CMD_RUN_ATH          ]*/ {_sm_inner_cmd_handle_ring_ATH},//挂断电话
    /*[CMD_HARD_REBOOT      ]*/ {_sm_inner_cmd_handle_hard_reboot}, //模块硬件重启
    /*[CMD_FLUSH_SMS        ]*/ {_sm_cmd_handle_SMS_flush},     //flush短信缓冲区
    /*[CMD_RES_SETUP_INFO   ]*/ {pdu_cmd_handle_resp_stat},      //回复命令处理结果
};

static option_t *l_option;
static uint8_t l_balance = 0; //话费余额

static void _sm_set_balance(uint8_t balance); //设置短信余额


    pdu_t *l_pdu_data = NULL; //解析pdu短信数据


/*设置话费余额*/
static void _sm_set_balance(uint8_t balance)
{
    l_balance = balance;
}

//==========================================================================================

//发送查询余额的短信
static int _sm_inner_cmd_handle_query(char cmd, char param)
{
    int ret = -1;
    if (SIM900A_api_get_COPS() == 1) //中国移动
    {
        ret = SMS_send_utf8_SM("10086", "YE", 2); //查余额
    }
    else if (SIM900A_api_get_COPS() == 2) //中国联通
    {
        ret = SMS_send_utf8_SM("10010", "YE", 2); //查余额
    }
    return ret;
}

//处理余额信息
static int _sm_inner_cmd_handle_balance(char cmd, char param)
{      
    char balance_value_str[10] = {0};
    char buffer[15] = {0};
    sprintf (balance_value_str, "%d", param);
    conv_pdu2asc (balance_value_str, buffer, strlen (balance_value_str));

    do
    {
        DBG_PRINTF ("日期：%d\n", SIM900A_get_monthday());
        /*SIM900A_gprs_send_tcp(3);*/

        if (SIM900A_get_monthday() >= 27) //27号以后
        {
            if (param <= 50 && (int8_t)param >= 0) //余额
            {
                break;
            }
        }
        else //27号以前
        {
            if (param <= 10 && (int8_t)param >= 0) //余额
            {
                break;
            }
        }
        return 0;
    }while(0);

    /*{++++++++++++发送余额不足报警++++++++++++*/
    _sm_set_balance(param);
    if (SIM900A_gprs_send_tcp(3) == -1)
    {
        DBG_PRINTF ("[第二次发送]%d\n", param);
        gprs_init(l_option->alarm_mode);
        if((SIM900A_gprs_send_tcp(3) == -1) 
                &&(SIM900A_gprs_send_tcp(3) == -1))
        {
            DBG_PRINTF ("[话费余额]%d\n", param);
            DBG_PRINTF ("[手机号]%s\n", SIM900A_get_telnum());
            SMS_cprintf (SIM900A_get_telnum(), "[温湿度报警器]温馨提示\n当前话费余额：%d元，为保证系统正常工作，请及时补充话费。", param);
        }
    }
    /*}------------发送余额不足报警------------*/
    return 0;
}


//设置系统时间
static int _sm_inner_cmd_handle_set_time(char cmd, char param)
{
    char string[35] = {0};
    if (SIM900A_get_year() == 0)
    {
        sprintf (string,"AT+CCLK=%s\r\n",l_time_cclk_string);
        SIM900A_run(string, 2000, NULL, NULL);
    }
    return 0;
}



//挂断来电
static int _sm_inner_cmd_handle_ring_ATH(char cmd, char param)
{
    SIM900A_run("ATH\r\n", 2000, NULL, NULL);
    return 0;
}

//检查+CREG字符串
static int __cb_check_sim_atreg(char *data, int len)
{
    object_t *tmp = NULL;
    char *key = "+CREG:";
    char *value = NULL;
    int ret = -1;
    char *result = strstr(data, key) + strlen(key);
    tmp = object_string_split(result, ',', NOQUOTES);
    value = object_string_get_field_string(tmp, 2);
    if (value != NULL)
    {
        if (value[0] != '1' && value[0] != '5')
        {
            ret = -55;//注册不成功
        }
        else
        {
            ret = 0;
        }
    }
    else
    {
        ret = -1;
    }
    object_free (tmp);
    return ret;
}

//检查并处理sim卡注册状态
#if (PLATFORM == LPC1114)
extern void display_telephone_state(uint8_t tel_state);
#endif
static int _sm_inner_cmd_handle_check_sim(char cmd, char param)
{
    int ret = -1;
    int count = 0;
    /*static int reboot_times = 0;*/
    do //检测注册网络
    {
        ret = SIM900A_run ("AT+CREG?\r\n", 2000, NULL, __cb_check_sim_atreg); //查询运营商信息
        if (ret == 0) {break;}//网络注册成功
        mdelay (1000);
        count ++;
    }
    while (ret != 0 && count < 3);
    if (ret == -55)
    {
        SIM900A_open();
        SIM900A_api_init ();
        /*reboot_times ++;*/
#if (PLATFORM == LPC1114)
        /*if (reboot_times >= 3)*/
        /*{*/
            /*display_telephone_state (4);*/
            /*reboot_times = 0;*/
        /*}*/
#endif
    }
    return 0;
}

static int _sm_inner_cmd_handle_call_phone(char cmd, char param)
{
    int recall_count = 0;   //拨号不成功时重拨的次数
    int call_ret = 0;      //拨号查是否成功

    do
    {
        mdelay (400);
        SIM900A_run("ATH\r\n", 3000, NULL, NULL); //准备拨号
        mdelay (100);
        call_ret = SIM900A_perform_formatted(10000, NULL, NULL, "ATD%s;\r\n", SIM900A_get_telnum()); //拨号
    }while(call_ret != AT_RETURN_OK && recall_count ++ <=30);
    return call_ret;
}

#if(PLATFORM == LPC1114)
extern void Initial_Lcd(void);
#endif
static int  _sm_inner_cmd_handle_hard_reboot(char cmd, char param)
{
    SIM900A_open ();
    SIM900A_api_init();
    gprs_init(l_option->alarm_mode);
#if(PLATFORM == LPC1114)
    NVIC_EnableIRQ (EINT1_IRQn);
    Initial_Lcd();
#endif
    return 0;
}

static int _sm_cmd_handle_SMS_flush(char cmd, char param) //flush短信缓冲区
{
    SMS_flush ();
    return 0;
}

 //初始化设置指针
/******************************************************************************
 * Function:        sm_init()
 * Description:     初始化设置全局参数指针
 * Calls:           cmd_fifo_init()
 * Called By:        
 * Input:           option  --全局参数变量指针
 * Others:          none
 *****************************************************************************/
void sm_init(option_t *option)
{
    if (option == NULL)
    {
        return;
    }
    l_option = option;
    cmd_fifo_init (l_inner_cmd_handle, DIM(l_inner_cmd_handle));
}

/******************************************************************************
 * Function:        sm_inner_cmd_loop()
 * Description:     内部命令主循环，执行主线程命令
 * Calls:           cmd_fifo_main_loop
 * Called By:       main()主函数
 * Input:           void
 * Return:          void
 * Others:          需要在主线程内周期性执行
 *****************************************************************************/
void sm_inner_cmd_loop()
{
    cmd_fifo_main_loop ();
}

/*******************************************************************************
 * Function:      sm_query_balance ()
 * Description:   从短信中获取"余额"字段的值
 * Calls:          
 * Called By:      
 * Input:         msg  --PDU UCS2文本
 * Return:        n   --余额值
 *                -1  --错误
 * Others:        None
 ******************************************************************************/
int sm_query_balance(char *msg)
{
    char *last = NULL;
    char *find = strstr(msg, "4F59989D");//匹配'余额'
    int value = -1;

    if (find != NULL) //匹配'余额'
    {
        last = (char *)calloc(1, strlen(msg)/2+1);
        if (last == NULL) return -1;
        *(find + 24) = '\0'; //限制匹配字符串长度
        conv_pdu2asc(strstr(find, "003"), last, 16); //匹配数字并转换
        value = atoi(last);
        free (last);
        sm_inner_cmd_push_fifo (CMD_PROC_BALANCE, value);
    }
    return value;
}

//查询余额
int sm_exec_query_balance()
{
    sm_inner_cmd_push_fifo (CMD_QUERY_BALANCE, 0);
    return 0;
}

/*使用CCLK格式设置时间*/
int sm_set_time (char * time)
{
    memset (l_time_cclk_string, 0, CCLK_TIME_STRING_BUFFER_LEN);
    strcpy (l_time_cclk_string, time);
    sm_inner_cmd_push_fifo (CMD_SET_SYS_TIME, 0);
    return 0;
}

//命令推入fifo
int sm_inner_cmd_push_fifo (cmd_id_t cmd, char param)
{
    cmd_fifo_add(cmd, param);
    return 0;
}

/*获得话费余额*/
uint8_t sm_get_balance()
{
    return  l_balance;
}

/*设置收信人*/
int sm_set_recipient(char *num)
{
    SMS_connect (num, strlen (num));
    return 0;
}


/*******************************************************************************
 * Function:      sm_parse_data()
 * Description:   分析短信数据
 * Calls:         conv_pdu2asc()
 *                sm_text_split2line_proc() 
 * Called By:      
 * Input:         data  --信息正文数据
 * Return:        void
 * Others:        msg 必须为可回写存储区,转换后字符串会回填到原位置
 ******************************************************************************/
int sm_parse_data(char *data)
{
    int ret = -1;
   // char *content = data;
    
    if (data == NULL || strlen (data) == 0) return -1;
    DBG_PRINTF ("短信正文PDU: %s\n", data);

    /*l_pdu_data = pdu_decode(data, strlen (data) -2); //字符串长度避开\n\r*/
    pdu_parse (data);
    /*sm_inner_cmd_push_fifo (8, 0);*/
    /*DBG_PRINTF ("短信正文PDU: %s\n", l_pdu_data->string);*/
    return ret;
}


//手机查询显示大棚数据指令句柄
static int _sm_inner_cmd_handle_view_dp(char cmd, char value)
{
    __view_dp_info (value, l_option);
    return 0;
}

//手机显示本机手机号码指令句柄
static int _sm_inner_cmd_handle_view_tel(char cmd, char value)
{
    __view_tel_num ();
    return 0;
}



#if(PLATFORM == LPC1114)
extern real_dp_d_t m_GreenHouse;
#endif
static int __view_dp_info(char value, option_t *option)
{

    int ret = 0;
    int i;
    int dp_num = (int) value;
    if (dp_num < 0 || dp_num > 20 || dp_num > option->number) //超过大棚数量范围
    {
        SMS_printf ("[错误]大棚序号超过现有大棚数\n");
    }
    else if (dp_num == 0)
    {
        SMS_printf ("查询所有大棚温湿度信息:\n");
        for (i = 1; i <= option->number; i ++)
        {
            SMS_printf("[大棚%02d]温度：%04.01f℃ 湿度：%04.01f％",
                    i,
#if(PLATFORM == LPC1114)
                    (float)m_GreenHouse.dp[i].temperature/10.0,
                    (float)m_GreenHouse.dp[i].humidity/10.0
#elif (PLATFORM == LINUX)
                    0,0
#endif          
                    );
            if (i < option->number)
                SMS_printf("\n");
        }
        if (i == 0)
        {
            SMS_printf ("[无大棚信息数据]");
        }
        ret = 0;
    }
    else
    {

        SMS_printf("[大棚%02d]\n实时温度：%04.01f℃(%02d℃～%02d℃)\n实时湿度：%04.01f％(%02d％～%02d％)\n",
                dp_num,
#if(PLATFORM == LPC1114)
                (float)m_GreenHouse.dp[dp_num].temperature/10.0,
#elif (PLATFORM == LINUX)
                0,
#endif
                option->dp[dp_num].temperature_low/10,
                option->dp[dp_num].temperature_high/10,
#if(PLATFORM == LPC1114)
                (float)m_GreenHouse.dp[dp_num].humidity/10.0,
#elif (PLATFORM == LINUX)
                0,
#endif
                option->dp[dp_num].humidity_low/10,
                option->dp[dp_num].humidity_high/10
                );
        /*printf("实时湿度：%d％（12％-23％）。\n", 2);*/
        ret = 0;
    }
    /*SMS_flush ();*/
    return ret;
}
 
//短信输出显示手机号
static int __view_tel_num(void)
{
    int i;
    SMS_printf ("报警手机号码："); //"手机号码:\n"
    for (i = 0; i < 11; i ++)
    {
        SMS_printf ("%d", l_option->telephone[0].number[i]);
    }
    SMS_flush ();
    return 0;
}

